package com.mutear.ParallelSearcher.sort;

import java.util.ArrayList;
import java.util.List;
import java.util.Collections;

import com.mutear.ParallelSearcher.utils.IResult;

public abstract class RankSort implements ISort {

	@Override
	public List<IResult> sort(List<IResult[]> results) {
		ArrayList<IResult> result = new ArrayList<IResult>();
		ArrayList<Double> distances = new ArrayList<Double>();
		for (int i = 0; i < results.size(); i++) {
			IResult[] iResults = results.get(i);
			for (int j = 0; j < iResults.length; j++) {
				int index = iResults[j].indexInList(result);
				if (index < 0) {
					result.add(iResults[j]);
					distances.add((double) j);
				} else {
					double weight = distances.get(index);
					if (weight != 0) {
						distances.set(index,
										(double) ((j % ((int) weight + 1)) + weight) / 2);
					}
					result.set(index,
							removeSimilar(result.get(index), iResults[j]));
				}
			}
		}

		for (int i = 0; i < result.size(); i++) {
			result.get(i).setDistance(distances.get(i));
		}

		return sortWithWeight(result);
	}

	private ArrayList<IResult> sortWithWeight(ArrayList<IResult> result) {
		int size = result.size();
		for (int i = 0; i < size; i++) {
			int s = size - i;
			for (int j = s / 2 - 1; j >= 0; j--) {
				int max = 0;
				if (2 * j + 2 < s
						&& result.get(2 * j + 1).getDistance() < result.get(
								2 * j + 2).getDistance()) {
					max = 1;
				}
				if (max == 0) {
					if (result.get(j).getDistance() < result.get(2 * j + 1)
							.getDistance()) {
						Collections.swap(result, j, 2 * j + 1);
					}
				} else {
					if (result.get(j).getDistance() < result.get(2 * j + 2)
							.getDistance()) {
						Collections.swap(result, j, 2 * j + 2);
					}
				}
			}
			Collections.swap(result, 0, s - 1);
		}
		return result;
	}

	@Override
	public abstract IResult removeSimilar(IResult arg0, IResult arg1);

}
